package org.pexx.components.classloader;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Hashtable;

import sun.misc.IOUtils;

//import modules.*;
public class DevelopmentClassLoader extends java.lang.ClassLoader  {
	
	private Hashtable<String, Class<?>> classes = new Hashtable<String, Class<?>>();

	private String basePath;
	
	public DevelopmentClassLoader(String basePath) {	
		super();
		this.basePath = basePath;
	}
	
	public void setBasePath(String basePath) {
		this.basePath = basePath;
	}
	
	public String getBasePath() {
		return basePath;
	}
	
	/* getClassPath (..)
	 * formatiert pfad und classennamen zu einem dateipfad
	 */
	private String getClassPath (String className) {
		
		if (className.endsWith(".class"))
			className = className.substring(0, className.length()-6);
		
		// format path
		String path = basePath.endsWith(File.separator) ? basePath : basePath + File.separator;
		
		// format filename
		String fileName = className.startsWith(".") ? className.substring(1) : className;
		fileName = className.replaceAll("\\.", File.separator) + ".class" ;
		
		// join them
		return path + fileName;
		
	}

	public byte[] loadClassData(String className) throws ClassNotFoundException  {

		String classPath = getClassPath (className);
		
		
		try {
			return getData (classPath);
		} catch (Exception e) {
			throw new ClassNotFoundException(e.getMessage());
		}
	}
	

	@Override
	public Class<?> findClass(String className) throws ClassNotFoundException  {
		Class<?> c;
		
		// class allrdy loaded?
		c = classes.get(className);		
		if (c != null) 
			return c; // yes -> return it
			
		
		byte classByte[] = loadClassData(className); // throws Ex. and interrupts execution
		
		if (classByte == null)
			throw new ClassNotFoundException ("classData for " + className + " NOT found!");
		
		// class data found --> try to transform into class
		c = defineClass(className, classByte, 0, classByte.length, null); // throws Ex. ... 		
		
		// class definition successfull
		classes.put(className, c); // save class
		
		return c; // bla
	}

	public byte[] getData(String dataPath) throws Exception {

		return load(this.getResourceAsStream(dataPath));		
		
		
	}
	
	private static byte[] concat (byte[] oldBuffer, byte[] newBuffer, int len) { // FIXED

		// bullshit from 1st semester ;)
		
//		int oldLen = oldBuffer.length;
//		byte[] ret = new byte[oldLen + len];
//		int i;		
//		for (i = 0; i < oldLen; i++) 
//			ret[i] = oldBuffer[i];
//		
//		
//		for (i = 0; i < len; i++) 
//			ret [i + oldLen] = newBuffer[i];
		
		byte[] ret = Arrays.copyOf(oldBuffer, oldBuffer.length + newBuffer.length);
		System.arraycopy(newBuffer, 0, ret, oldBuffer.length, newBuffer.length);
		
		return ret;
	}
	
	public static byte[] load(InputStream stream) throws IOException {
		
		// bullshit too
		
//		byte[] r = new byte[1024];
//		byte[] t = new byte[0];
//		
//		int len = -1;
//		
//		while ((len = stream.read(r)) > 0)
//			t = concat (t, r, len);		
		
		
		return IOUtils.readFully(stream, -1, true);
		         
	}
}